#include "Sock.hpp"
#include<sys/select.h>

#define NUM (sizeof(fd_set) * 8)

int fd_array[NUM]; //内容大于0，合法的fd，如果是-1,该位置没有fd

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        cout << "Usage:\n\t" << "port" << endl;
        exit(1);
    }

    int listen_sock = sock::Socket();
    sock::Bind(listen_sock, atoi(argv[1]));
    sock::Listen(listen_sock);
    for(int i = 0; i < NUM; i++)
    {
        fd_array[i] = -1;
    }
    //为什么我们接下来不直接accept,因为在我们accept的时候文件已经就绪了，现在我们是为了通过多路转接等待多个文件，我们要先通过select等待已经就绪的文件才能accept。
    //事件循环
    fd_set rfds;//文件描述符位图
    fd_array[0] = listen_sock;
    while(1)
    {
        FD_ZERO(&rfds);
        int max_fd = fd_array[0];
        for(int i = 0; i < NUM; i++)
        {
            if(fd_array[i] == -1)
            {
                continue;
            }
            //下面是合法的fd
            FD_SET(fd_array[i], &rfds);//所有要关心读事件的fd，添加到rfds中
            if(max_fd < fd_array[i])
            {
                max_fd = fd_array[i];
            }
        }
        struct timeval timeout = {0,0};//阻塞时间
        //我们的服务器上的所有的fd（包括listen_sock）,都要交给select检测;
        //recv,read,write,send,accept:只负责自己最核心的工作，真正的读写（listen_sock:accept）
        int n = select(max_fd + 1, &rfds, nullptr, nullptr, nullptr);
        switch(n)
        {
            case -1:
                cerr << "select error" << endl;
                break;
            case 0:
                cerr << "select timeout" << endl;
                break;
            default:
                cout << "有fd对应的事件就绪了!" << endl;
                for(int i = 0; i < NUM; i++)
                {
                    if(fd_array[i] == -1)
                    {
                        continue;
                    }
                    if(FD_ISSET(fd_array[i], &rfds))
                    {
                        cout << "sock: " << fd_array[i] << " 上面有了读事件，可以读取了" << endl;
                        //一定是读事件就绪了。
                        //就绪的fd就在fd_array[i]中保存。
                        //read,recv时，一定不被阻塞。
                        if(fd_array[i] == listen_sock)
                        {
                            cout << "listen_sock: " << listen_sock << "有了新的连接到来" << endl;
                            //accept
                            int sock = sock::Accept(listen_sock);
                            if(sock >= 0)
                            {
                                cout << "listen_sock: " << listen_sock << "获取新的连接成功" << endl;
                                //获取成功
                                //新连接到来，不意味有数据到来
                                //但是我们可以知道select最清楚哪些fd可以读取数据，虽然我们无法直接将fd设置进select,但是我们可以设置进fd_array数组，下一次读取。
                                int pos = 1;
                                for(; pos < NUM; pos++)
                                {
                                    if(fd_array[pos] == -1)
                                    {
                                        break;
                                    }
                                }
                                //1.找到了一个位置没有被使用
                                //2.找完了所有的位置，都没有找到没有被用的位置
                                if(pos < NUM)
                                {
                                    cout << "新连接: " << sock << "已经添加到了数组[" << pos << "]的位置" << endl;
                                    fd_array[pos] = sock;
                                }
                                else
                                {
                                    //说明服务器已经满载，没法处理新的请求
                                    cout << "服务器已经满载了，关闭新的连接" << endl;
                                    close(sock);
                                }
                            }
                        }                       
                        else
                        {
                            //read,recv
                            //注意读取的时候也要构建协议，比如怎么读取避免粘包问题，如果一次读不完，一次该读多少数据。
                            cout << "sock: " << fd_array[i] << "上面有普通数据读取" << endl;
                            char recv_buffer[1024] = {0};
                            ssize_t s = recv(fd_array[i], recv_buffer, sizeof(recv_buffer) - 1, 0);
                            if(s > 0)
                            {
                                recv_buffer[s] = '\0';
                                cout << "client[ " << fd_array[i] << "]# " << recv_buffer << endl;
                            }
                            else if(s == 0)
                            {
                                cout << "sock: " << fd_array[i] << "关闭了，client退出了" << endl;
                                //对端关闭了连接
                                close(fd_array[i]);
                                

                                cout << "已经在数组下标fd_array[" << i << "]中去掉了sock: " << fd_array[i] << endl;
                                fd_array[i] = -1;
                            }
                            else
                            {
                                //读取失败
                                close(fd_array[i]);
                                

                                cout << "已经在数组下标fd_array[" << i << "]中去掉了sock: " << fd_array[i] << endl;
                                fd_array[i] = -1;
                            }
                        }
                    }
                }
                break;
        }
    }

    return 0;

}
